package org.simplextensions.scanner.impl;

import javassist.bytecode.ClassFile;
import org.simplextensions.scanner.ClassFileIterator;
import org.simplextensions.scanner.ClassScannerBundle;
import org.simplextensions.scanner.ClasspathScannerException;
import org.simplextensions.scanner.IClassScanner;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 
 * @author Tomasz Krzyzak, <a
 *         href="mailto:tomasz.krzyzak@gmail.com">tomasz.krzyzak@gmail.com</a>
 * @since 31-08-2010 21:21:23
 */
public class JarCSB extends ClassScannerBundle {

	private final JarFile jarFile;

	public class JarClassFileIterator extends ClassFileIterator {

		private Enumeration<JarEntry> files2Process;

		public JarClassFileIterator(JarCSB csb) {
			super(csb);
			files2Process = csb.getJarFile().entries();
		}

		protected ClassFile searchNext() {
			ClassFile result = null;

			while (result == null && files2Process.hasMoreElements()) {
				JarEntry nextJarEntry = files2Process.nextElement();

				String name = nextJarEntry.getName();
				if (!name.endsWith(".class"))
					continue;

                name = name.substring(0, name.length()-6).replace("/",".");

                if (getClassNames()!=null && getClassNames().size()>0 && !getClassNames().contains(name))
                    continue;

				InputStream inputStream = null;
				try {
					inputStream = getJarFile().getInputStream(nextJarEntry);
					result = new ClassFile(new DataInputStream(inputStream));
				} catch (Exception e) {
					throw new ClasspathScannerException(name, e);
				} finally {
					if (inputStream != null)
						try {
							inputStream.close();
						} catch (IOException e) {
							// no need to do anything
						}
				}
			}

			return result;
		}

	}

	public JarCSB(String name, JarFile jarFile, Map<String, Map<Integer, List<IClassScanner>>> scanListeners, Set<String> classNames) {
		super(name, scanListeners, classNames);
		this.jarFile = jarFile;
	}

	public Iterator<ClassFile> classFileIterator() {
		return new JarClassFileIterator(this);
	}

	JarFile getJarFile() {
		return this.jarFile;
	}

}
